package org.jeecg.modules.wms.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.modules.wms.entity.WmsInventory;
import org.jeecg.modules.wms.entity.WmsMaterial;
import org.jeecg.modules.wms.service.IWmsInventoryService;
import org.jeecg.modules.wms.service.IWmsMaterialService;
import org.jeecg.modules.wms.vo.WmsInventoryAdjustVO;
import org.jeecg.modules.wms.vo.WmsInventoryMoveVO;
import org.jeecg.modules.wms.vo.WmsInventoryVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 库存管理
 */
@Slf4j
@Api(tags = "库存管理")
@RestController
@RequestMapping("/wms/inventory")
public class WmsInventoryController extends JeecgController<WmsInventory, IWmsInventoryService> {

    @Autowired
    private IWmsInventoryService inventoryService;

    @Autowired
    private IWmsMaterialService materialService;

    /**
     * 分页列表查询
     */
    @AutoLog(value = "库存管理-分页列表查询")
    @ApiOperation(value = "库存管理-分页列表查询", notes = "库存管理-分页列表查询")
    @GetMapping(value = "/list")
    public Result<IPage<WmsInventoryVO>> queryPageList(WmsInventoryVO inventory,
                                                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                       HttpServletRequest req) {
        Map<String, Object> query = new HashMap<>();

        // 构建查询条件
        if (inventory != null) {
            if (StringUtils.isNotBlank(inventory.getMaterialCode())) {
                // 物料编号模糊查询
                query.put("materialCode", inventory.getMaterialCode());
            }
            if (StringUtils.isNotBlank(inventory.getMaterialName())) {
                query.put("materialName", inventory.getMaterialName());
            }
            if (inventory.getMaterialType() != null) {
                query.put("materialType", inventory.getMaterialType().toString());
            }
            if (StringUtils.isNotBlank(inventory.getWarehouseId())) {
                query.put("warehouseId", inventory.getWarehouseId());
            }
            if (StringUtils.isNotBlank(inventory.getLocationId())) {
                query.put("locationId", inventory.getLocationId());
            }
            if (StringUtils.isNotBlank(inventory.getBatchNo())) {
                query.put("batchNo", inventory.getBatchNo());
            }
            if (inventory.getStockStatus() != null) {
                query.put("stockStatus", inventory.getStockStatus());
            }
            if(inventory.getMaterialSeries() != null){
                query.put("materialSeries", inventory.getMaterialSeries());
            }
            if(inventory.getColor() != null){
                query.put("color", inventory.getColor());
            }
        }

        Page<WmsInventoryVO> page = new Page<>(pageNo, pageSize);
        IPage<WmsInventoryVO> pageList = inventoryService.queryInventoryPageList(page, query);
        return Result.OK(pageList);
    }

    /**
     * 添加
     */
    @AutoLog(value = "库存管理-添加")
    @ApiOperation(value = "库存管理-添加", notes = "库存管理-添加")
    @PostMapping(value = "/add")
    public Result<String> add(@RequestBody WmsInventory inventory) {
        inventoryService.save(inventory);
        return Result.OK("添加成功！");
    }

    /**
     * 编辑
     */
    @AutoLog(value = "库存管理-编辑")
    @ApiOperation(value = "库存管理-编辑", notes = "库存管理-编辑")
    @PutMapping(value = "/edit")
    public Result<String> edit(@RequestBody WmsInventory inventory) {
        inventoryService.updateById(inventory);
        return Result.OK("编辑成功!");
    }

    /**
     * 通过id删除
     */
    @AutoLog(value = "库存管理-通过id删除")
    @ApiOperation(value = "库存管理-通过id删除", notes = "库存管理-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
        inventoryService.removeById(id);
        return Result.OK("删除成功!");
    }

    /**
     * 批量删除
     */
    @AutoLog(value = "库存管理-批量删除")
    @ApiOperation(value = "库存管理-批量删除", notes = "库存管理-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        this.inventoryService.removeByIds(Arrays.asList(ids.split(",")));
        return Result.OK("批量删除成功！");
    }

    /**
     * 通过id查询
     */
    @AutoLog(value = "库存管理-通过id查询")
    @ApiOperation(value = "库存管理-通过id查询", notes = "库存管理-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<WmsInventory> queryById(@RequestParam(name = "id", required = true) String id) {
        WmsInventory inventory = inventoryService.getById(id);
        return Result.OK(inventory);
    }

    /**
     * 入库
     */
    @AutoLog(value = "库存管理-入库")
    @ApiOperation(value = "库存管理-入库", notes = "库存管理-入库")
    @PostMapping(value = "/inbound")
    public Result<String> inbound(@RequestBody WmsInventory inventory,
                                  @RequestParam(name = "quantity", required = true) BigDecimal quantity,
                                  @RequestParam(name = "businessType", required = true) Integer businessType,
                                  @RequestParam(name = "businessNo", required = true) String businessNo,
                                  @RequestParam(name = "operator", required = true) String operator,
                                  @RequestParam(name = "remark", required = false) String remark) {
        // 提示用户使用新的入库单接口
        return Result.error("为保证库存数据准确性，请使用入库单功能进行入库操作。路径：/wms/inboundOrder/add");
    }

    /**
     * 出库
     */
    @AutoLog(value = "库存管理-出库")
    @ApiOperation(value = "库存管理-出库", notes = "库存管理-出库")
    @PostMapping(value = "/outbound")
    public Result<String> outbound(@RequestBody WmsInventory inventory,
                                   @RequestParam(name = "quantity", required = true) BigDecimal quantity,
                                   @RequestParam(name = "businessType", required = true) Integer businessType,
                                   @RequestParam(name = "businessNo", required = true) String businessNo,
                                   @RequestParam(name = "operator", required = true) String operator,
                                   @RequestParam(name = "remark", required = false) String remark) {
        boolean result = inventoryService.outbound(inventory, quantity, businessType, businessNo, operator, remark);
        if (result) {
            return Result.OK("出库成功！");
        } else {
            return Result.error("出库失败！");
        }
    }

    /**
     * 库存调整
     */
    @AutoLog(value = "库存管理-库存调整")
    @ApiOperation(value = "库存管理-库存调整", notes = "库存管理-库存调整")
    @PostMapping(value = "/adjust")
    public Result<String> adjust(@RequestBody WmsInventoryAdjustVO adjustVO) {
        if (adjustVO == null || adjustVO.getInventory() == null || adjustVO.getQuantity() == null) {
            return Result.error("参数不完整");
        }

        boolean result = inventoryService.adjust(adjustVO.getInventory(), adjustVO.getQuantity(),
                adjustVO.getBusinessType(), adjustVO.getBusinessNo(), adjustVO.getOperator(), adjustVO.getRemark());

        if (result) {
            return Result.OK("库存调整成功！");
        } else {
            return Result.error("库存调整失败！");
        }
    }

    /**
     * 库存移动
     */
    @AutoLog(value = "库存管理-库存移动")
    @ApiOperation(value = "库存管理-库存移动", notes = "库存管理-库存移动")
    @PostMapping(value = "/move")
    public Result<String> move(@RequestBody WmsInventoryMoveVO moveVO) {
        if (moveVO == null || moveVO.getInventory() == null || moveVO.getQuantity() == null
                || StringUtils.isBlank(moveVO.getTargetWarehouseId())) {
            return Result.error("参数不完整");
        }

        // 生成业务单号
        if (StringUtils.isBlank(moveVO.getBusinessNo())) {
            moveVO.setBusinessNo("MOVE-" + System.currentTimeMillis());
        }

        boolean result = inventoryService.move(moveVO.getInventory(), moveVO.getTargetWarehouseId(),
                moveVO.getTargetLocationId(), moveVO.getQuantity(), moveVO.getOutboundBusinessType(),
                moveVO.getInboundBusinessType(), moveVO.getBusinessNo(), moveVO.getOperator(), moveVO.getRemark());

        if (result) {
            return Result.OK("库存移动成功！");
        } else {
            return Result.error("库存移动失败！");
        }
    }

    /**
     * 入库（带成本）
     * <p>
     * 业务规则：
     * 1. 一个库位只能存放一种物料，若库位已存在其他物料则会报错
     * 2. 当物料编号、库位信息一致时，会对库存数量进行累加计算，而非新增库存记录
     * 3. 入库会自动计算平均单位成本和总成本
     */
    @AutoLog(value = "库存管理-带成本的入库")
    @ApiOperation(value = "库存管理-带成本的入库", notes = "库存管理-带成本的入库 - 一个库位只能存放一种物料，相同物料和库位会累加库存")
    @PostMapping(value = "/inboundWithCost")
    public Result<String> inboundWithCost(@RequestBody WmsInventoryVO inventoryVO) {
        // 提示用户使用新的入库单接口
        return Result.error("为保证库存数据准确性，请使用入库单功能进行入库操作。路径：/wms/inboundOrder/add");
    }

    /**
     * 带成本的出库
     */
    @AutoLog(value = "库存管理-带成本的出库")
    @ApiOperation(value = "库存管理-带成本的出库", notes = "库存管理-带成本的出库")
    @PostMapping(value = "/outboundWithCost")
    public Result<String> outboundWithCost(@RequestBody WmsInventory inventory,
                                           @RequestParam(name = "quantity", required = true) BigDecimal quantity,
                                           @RequestParam(name = "businessType", required = true) Integer businessType,
                                           @RequestParam(name = "businessNo", required = true) String businessNo,
                                           @RequestParam(name = "operator", required = true) String operator,
                                           @RequestParam(name = "remark", required = false) String remark) {
        boolean result = inventoryService.outboundWithCost(inventory, quantity, businessType, businessNo, operator, remark);
        if (result) {
            return Result.OK("出库成功！");
        } else {
            return Result.error("出库失败！");
        }
    }

    /**
     * 库存成本调整
     */
    @AutoLog(value = "库存管理-库存成本调整")
    @ApiOperation(value = "库存管理-库存成本调整", notes = "库存管理-库存成本调整")
    @PostMapping(value = "/adjustCost")
    public Result<String> adjustCost(@RequestBody WmsInventory inventory,
                                     @RequestParam(name = "newUnitCost", required = true) BigDecimal newUnitCost,
                                     @RequestParam(name = "businessType", required = true) Integer businessType,
                                     @RequestParam(name = "businessNo", required = true) String businessNo,
                                     @RequestParam(name = "operator", required = true) String operator,
                                     @RequestParam(name = "remark", required = false) String remark) {
        boolean result = inventoryService.adjustCost(inventory, newUnitCost, businessType, businessNo, operator, remark);
        if (result) {
            return Result.OK("成本调整成功！");
        } else {
            return Result.error("成本调整失败！");
        }
    }

    /**
     * 查询物料在特定仓库的库存
     */
    @AutoLog(value = "库存管理-查询物料在特定仓库的库存")
    @ApiOperation(value = "库存管理-查询物料在特定仓库的库存", notes = "库存管理-查询物料在特定仓库的库存")
    @GetMapping(value = "/queryByMaterialAndWarehouse")
    public Result<List<WmsInventoryVO>> queryByMaterialAndWarehouse(
            @RequestParam(name = "materialId", required = true) String materialId,
            @RequestParam(name = "warehouseId", required = true) String warehouseId) {

        log.info("查询物料在仓库的库存, materialId: {}, warehouseId: {}", materialId, warehouseId);

        // 参数校验
        if (StringUtils.isBlank(materialId) || StringUtils.isBlank(warehouseId)) {
            return Result.error("物料ID和仓库ID不能为空");
        }

        try {
            // 调用服务查询库存
            List<WmsInventoryVO> inventoryList = inventoryService.queryByMaterialAndWarehouse(materialId, warehouseId);
            return Result.OK(inventoryList);
        } catch (Exception e) {
            log.error("查询物料库存失败", e);
            return Result.error("查询物料库存失败: " + e.getMessage());
        }
    }

    /**
     * 根据物料编号、物料类型和出库数量查询可用库存信息
     */
    @AutoLog(value = "库存管理-查询可用库存信息")
    @ApiOperation(value = "库存管理-查询可用库存信息", notes = "库存管理-查询可用库存信息")
    @GetMapping(value = "/queryAvailableInventory")
    public Result<List<WmsInventoryVO>> queryAvailableInventory(
            @RequestParam(name = "materialCode", required = true) String materialCode,
            @RequestParam(name = "materialType", required = false) String materialType,
            @RequestParam(name = "requiredQuantity", required = true) BigDecimal requiredQuantity) {

        log.info("查询可用库存信息，物料编号: {}, 物料类型: {}, 需求数量: {}", materialCode, materialType, requiredQuantity);

        try {
            // 调用服务查询可用库存
            List<WmsInventoryVO> availableInventoryList = inventoryService.queryAvailableInventoryForOutbound(
                    materialCode, materialType, requiredQuantity);

            log.info("查询到 {} 条可用库存记录", availableInventoryList.size());
            return Result.OK(availableInventoryList);
        } catch (Exception e) {
            log.error("查询可用库存信息失败", e);
            return Result.error("查询可用库存信息失败: " + e.getMessage());
        }
    }

    /**
     * 移动端库存查询接口 - 支持折叠显示和模糊搜索
     */
    @AutoLog(value = "库存管理-移动端查询")
    @ApiOperation(value = "库存管理-移动端查询", notes = "库存管理-移动端查询，支持折叠显示和模糊搜索")
    @GetMapping(value = "/queryForMobile")
    public Result<IPage<WmsInventoryVO>> queryForMobile(
            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
            @RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize,
            @RequestParam(name = "searchKeyword", required = false) String searchKeyword,
            @RequestParam(name = "materialTypes", required = false) String materialTypes,
            @RequestParam(name = "warehouseName", required = false) String warehouseName,
            @RequestParam(name = "locationCode", required = false) String locationCode,
            @RequestParam(name = "materialCode", required = false) String materialCode,
            @RequestParam(name = "materialName", required = false) String materialName,
            @RequestParam(name = "specification", required = false) String specification,
            @RequestParam(name = "color", required = false) String color,
            HttpServletRequest req) {
        try {
            Map<String, Object> query = new HashMap<>();

            // 具体字段模糊查询
            if (StringUtils.isNotBlank(warehouseName)) {
                query.put("warehouseName", warehouseName.trim());
            }
            if (StringUtils.isNotBlank(locationCode)) {
                query.put("locationCode", locationCode.trim());
            }
            if (StringUtils.isNotBlank(materialCode)) {
                query.put("materialCode", materialCode.trim());
            }
            if (StringUtils.isNotBlank(materialName)) {
                query.put("materialName", materialName.trim());
            }
            if (StringUtils.isNotBlank(specification)) {
                query.put("specification", specification.trim());
            }
            if (StringUtils.isNotBlank(color)) {
                query.put("color", color.trim());
            }

            // 物料类型筛选
            if (StringUtils.isNotBlank(materialTypes)) {
                String[] typeArray = materialTypes.split(",");
                List<String> typeList = new ArrayList<>();
                for (String type : typeArray) {
                    typeList.add(type.trim());
                }
                query.put("materialTypes", typeList);
            }


            Page<WmsInventoryVO> page = new Page<>(pageNo, pageSize);
            IPage<WmsInventoryVO> pageList = inventoryService.queryInventoryForMobile(page, query);

            log.info("移动端库存查询完成，返回 {} 条记录", pageList.getRecords().size());
            return Result.OK(pageList);

        } catch (Exception e) {
            log.error("移动端库存查询失败", e);
            return Result.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 导出库存列表
     */
    @AutoLog(value = "库存管理-导出库存列表")
    @ApiOperation(value = "库存管理-导出库存列表", notes = "库存管理-导出库存列表")
    @GetMapping(value = "/exportInventoryList")
    public void exportInventoryList(WmsInventoryVO inventory,
                                   HttpServletRequest request,
                                   HttpServletResponse response) {
        try {
            // 构建查询条件
            Map<String, Object> query = new HashMap<>();
            if (inventory != null) {
                if (StringUtils.isNotBlank(inventory.getMaterialCode())) {
                    query.put("materialCode", inventory.getMaterialCode());
                }
                if (StringUtils.isNotBlank(inventory.getMaterialName())) {
                    query.put("materialName", inventory.getMaterialName());
                }
                if (inventory.getMaterialType() != null) {
                    query.put("materialType", inventory.getMaterialType().toString());
                }
                if (StringUtils.isNotBlank(inventory.getWarehouseId())) {
                    query.put("warehouseId", inventory.getWarehouseId());
                }
                if (StringUtils.isNotBlank(inventory.getLocationId())) {
                    query.put("locationId", inventory.getLocationId());
                }
                if (StringUtils.isNotBlank(inventory.getBatchNo())) {
                    query.put("batchNo", inventory.getBatchNo());
                }
                if (inventory.getStockStatus() != null) {
                    query.put("stockStatus", inventory.getStockStatus());
                }
                if (inventory.getMaterialSeries() != null) {
                    query.put("materialSeries", inventory.getMaterialSeries());
                }
                if (inventory.getColor() != null) {
                    query.put("color", inventory.getColor());
                }
            }

            // 调用服务层导出方法
            inventoryService.exportInventoryList(query, response);
            
        } catch (Exception e) {
            log.error("导出库存列表失败", e);
            try {
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().write("{\"success\":false,\"message\":\"导出失败: " + e.getMessage() + "\"}");
            } catch (IOException ioException) {
                log.error("写入错误响应失败", ioException);
            }
        }
    }
}